Skip to content

fix: validate ttl_nanos when reusing a shared region across processes (#42)#80

Merged
toloco merged 1 commit into
masterfrom
fix/42-ttl-validation
Jun 18, 2026
Merged

fix: validate ttl_nanos when reusing a shared region across processes (#42)#80
toloco merged 1 commit into
masterfrom
fix/42-ttl-validation

Conversation

@toloco

@toloco toloco commented Jun 18, 2026

Copy link
Copy Markdown
Owner

Closes #42

What & why

region.rs::create_or_open decides whether to reuse an existing shm region by comparing version, capacity, max_key_size, and max_value_size — but not ttl_nanos. TTL lives in the shared header and is read at lookup time (shm/mod.rs: h.ttl_nanos), governing expiry for every process. So when process B opens a cache that process A created with a different TTL:

  • A: cache(backend="shared", ttl=10)(f)
  • B (same shm_name): cache(backend="shared", ttl=None)(f) → silently reuses A's region; B's entries expire per ttl=10, not None.

Same decorator params → different effective behavior depending on who won the create race, and inconsistent with the other config params (which already force a recreate on mismatch).

The fix

Add header.ttl_nanos == ttl_nanos to the reuse condition, so a TTL mismatch recreates the region — same last-writer-wins behavior as a capacity/key/value-size mismatch.

Test

TestSharedTTLConfigMismatch::test_ttl_mismatch_recreates_region: construct a region with ttl=0.1, then construct again on the same shm_name with ttl=None; an entry stored by the second must survive past 0.1s. The bug lives in the reuse decision (hit on the second construction, same code path in-process or cross-process), so a single-process test covers it deterministically.

Verified fail-before → pass-after by stashing just the fix: buggy build gave hits=0, misses=2 (entry expired per the creator's ttl=0.1); with the fix, hits=1.

Drive-by doc fix (disclosed)

While adding the #42 invariant I found a merge artifact in docs/ARCHITECTURE.md: the issue #37 invariant text had been stranded as a duplicated alignment padding; … fragment after the #40 bullet (a result of #76 and #77 landing together). I folded it back into the #[repr(C)] bullet where it belongs. Pure docs, no behavior — happy to split into its own PR if you'd prefer.

Gates run (risky change — src/shm/region.rs)

  • make fmt / make lint (ruff, ty, clippy -D warnings) ✓
  • make testcargo test (11) + pytest (102, +1 new) ✓
  • make test-matrix — Python 3.10–3.13 ✓, new test passes on each (3.14 skipped locally via the documented uv-resolves-stale-alpha guard; CI covers 3.14 final)
  • make bench — no regression (construction-time-only change): shared backend ~9.4M ops/s, hit-rate 72.9%

🤖 Generated with Claude Code

…#42)

create_or_open's reuse check compared version, capacity, max_key_size, and
max_value_size but not ttl_nanos. A process opening an existing shared cache
with a different TTL (e.g. ttl=None when the creator used ttl=10) silently
reused the creator's region and inherited its TTL from the shared header —
expiry is read from h.ttl_nanos at lookup time, so the second process's
requested TTL was ignored. Same decorator params produced different effective
behavior depending on which process won the create race, and it was
inconsistent with the other config params (which force a recreate on mismatch).

Add `header.ttl_nanos == ttl_nanos` to the reuse condition so a TTL mismatch
recreates the region, exactly like a capacity/key/value-size mismatch
(last-writer-wins).

Add a regression test: a region created with ttl=0.1 then opened with ttl=None
must honor ttl=None (entry survives past 0.1s) — before the fix it expired per
the creator's TTL. The bug is in the reuse decision, exercised on the second
construction, so a single-process test covers it deterministically.

Also repair a merge artifact in ARCHITECTURE.md: the issue #37 invariant text
had been stranded as a duplicated fragment after the #40 bullet (from #76 and
#77 landing together); fold it back into the #[repr(C)] bullet. Document the
config-gates-reuse invariant.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@toloco toloco merged commit c09b4f9 into master Jun 18, 2026
14 checks passed
@toloco toloco deleted the fix/42-ttl-validation branch June 18, 2026 09:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[medium] create_or_open validates capacity/key/value sizes but NOT ttl_nanos across processes

1 participant